﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using Newtonsoft.Json.Serialization;
using Sharp.Platform;
using Sharp.Platform.Mvc;
using Sharp.Platform.Interface;
using Sharp.Platform.List;
using Sharp.Platform.Mvc.Attribute;
using ColumnAttribute = Sharp.Platform.ColumnAttribute;
using TemplateColumnAttribute = Sharp.Platform.TemplateColumnAttribute;
using Sharp.Platform.Mvc.Models;
using System.Collections.Concurrent;

namespace Sharp.WebBooter
{
    /// <summary>
    /// ExtNet模板适配器
    /// </summary>
    public class BSTemplateProvider : ITemplateProvider
    {
        #region 新增
        /// <summary>
        /// 新增
        /// </summary>
        /// <returns></returns>
        public string Create(object model)
        {
            if (model == null)
            {
                return string.Empty;
            }
            StringBuilder sb = new StringBuilder();

            Rendering(sb, model, "添加");

            return sb.ToString();
        }
        #endregion

        #region 编辑
        /// <summary>
        /// 编辑
        /// </summary>
        /// <returns></returns>
        public string Edit(object model)
        {
            if (model == null)
            {
                return string.Empty;
            }
            StringBuilder sb = new StringBuilder();

            Rendering(sb, model, "修改");

            return sb.ToString();
        }
        #endregion

        #region 详情
        /// <summary>
        /// 详情
        /// </summary>
        /// <returns></returns>
        public string Details(object model)
        {
            if (model == null)
            {
                return string.Empty;
            }
            StringBuilder sb = new StringBuilder();
            Rendering(sb, model, "详情");
            return sb.ToString();
        }
        #endregion

        #region 主页
        /// <summary>
        /// 主页
        /// </summary>
        /// <returns></returns>
        public string Index(object model)
        {
            if (model == null)
            {
                return string.Empty;
            }

            if (model is ISharpTreeList)
            {
                return IndexTree(model);
            }

            var dataList = (ISharpList)model;
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("@model {0}\r\n", model.GetType().FullName);

            sb.AppendLine("@using Sharp.WebBooter");
            sb.AppendLine("<section class=\"content-header\">");
            sb.AppendLine("<h1>");
            sb.Append(dataList.GetTitle());
            sb.Append("</h1>");


            sb.AppendLine("<ol class=\"breadcrumb\">");
            sb.AppendLine("<li><a href =\"@Url.Action(\"Index\", \"Home\")\"><i class=\"fa fa-home\"></i> 首页</a></li>");
            sb.AppendLine("<li class=\"active\">VIU</li>");
            sb.AppendLine("</ol>");
            sb.AppendLine("</section>");
            sb.AppendLine("<section class=\"content\">");
            sb.AppendLine("<div class=\"row\">");
            sb.AppendLine("<div class=\"col-lg-12\">");
            sb.AppendLine("<div class=\"box box-primary\">");
            sb.AppendLine("<div class=\"box-header with-border\">");

            if (!dataList.Feature.HasFlag(ListFeature.HiddenToolButton))
            {
                sb.AppendLine("<div class=\"dataTable-tools btn-group\">");

                //渲染工具栏按钮
                var toolButtons = string.Join("\r\n", dataList.GetToolButtons(model).Select(x => x.Html));
                sb.AppendLine(toolButtons);
                sb.AppendLine("</div>");
            }


            sb.AppendLine("<div class=\"box-tools SearchArea\">");
            sb.AppendLine("<div class=\"input-group input-group-sm\" style=\"width:150px;float:right;\">");

            foreach (var column in GetColumnInfos(model))
            {
                if (column.Value.SearchFor)
                {
                    sb.AppendFormat("<input type =\"text\" name=\"{0}\" class=\"form-control pull-right\" placeholder=\"{1}\">\r\n", column.Key, column.Value.Text);
                }
            }
            sb.AppendLine("<div class=\"input-group-btn\">");
            sb.AppendLine("<button type =\"button\" class=\"btn btn-default\" onclick=\"window.app.search();\"><i class=\"fa fa-search\"></i></button>");
            if (GetColumnInfos(model).Any(x => !x.Value.SearchFor))
            {
                sb.AppendLine("<button type=\"button\" class=\"btn btn-default\" title=\"高级查询\" id=\"toggle-advanced-search\"><i class=\"fa fa-angle-double-down\"></i></button>");
            }
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");

            //高级搜索
            if (GetColumnInfos(model).Any(x => !x.Value.SearchFor))
            {
                sb.AppendLine("<div id=\"div-advanced-search\" class=\"row\" style=\"display: none;\">");
                sb.AppendLine("<div class=\"col-lg-12 SearchArea\">");
                sb.AppendLine("<form class=\"form-inline well-sm\" style=\"line-height:38px;\">");
                foreach (var column in GetColumnInfos(model).Where(x => !x.Value.SearchFor))
                {
                    sb.AppendFormat("<div class=\"col-md-3 text-right\"><span>{0}：</span>", column.Value.Text.IsNullOrEmpty() ? column.Key : column.Value.Text);
                    sb.AppendFormat("<input type=\"text\" name=\"{0}\" placeholder=\"{1}\" class=\"form-control\"></div>", column.Key, column.Value.Text);
                }

                sb.AppendLine("<div class=\"col-md-3 text-center\"><button id=\"btn-advanced-search\" class=\"btn btn-default\" type=\"button\" onclick=\"window.app.search();\"><i class=\"fa fa-search\"></i> 查询</button></div>");
                sb.AppendLine("</form></div></div>");

                sb.AppendLine(
                    "<script> $(\"#toggle-advanced-search\").click(function () { $(\"i\", this).toggleClass(\"fa-angle-double-down fa-angle-double-up\"); $(\"#div-advanced-search\").slideToggle(\"fast\"); });</script>");
            }

            sb.AppendLine("</div>");
            sb.AppendLine("<div class=\"box-body no-padding\">");


            sb.AppendLine("<div class=\"table-responsive\">");
            sb.AppendLine("<table id =\"dataList\" class=\"table table-bordered table-condensed table-striped table-hover dataTable text-center\" width=\"100%\"></table>");
            sb.AppendLine("</div></div></div></div></div>");
            sb.AppendLine("</section>");

            sb.AppendLine("<script type=\"text/javascript\">");
            sb.AppendLine("$(document).ready(function () {");

            sb.AppendLine("$('#dataList').dataTable({");
            sb.AppendLine("\"serverSide\": true,");
            sb.AppendLine("\"ajax\": { \"url\": \"@Url.Action(\"GetPaged\")\", \"type\": \"POST\" },");
            sb.AppendLine("\"columnDefs\": [ { sDefaultContent: '', aTargets: ['_all'] },");
            sb.AppendLine("{ \"searchable\": false, sortable: false, \"orderable\": false, \"targets\": [-1, 0, 1, 2] },");
            sb.AppendLine("{ \"sClass\": \"editableCol\", \"aTargets\": [1] } ],");
            sb.AppendLine("columns: [");

            if (dataList.Feature.HasFlag(ListFeature.MultiSelect))
            {
                sb.AppendLine("{ title: '<label class=\"checkbox i-checks\"><input type=\"checkbox\" /><i></i></label>', data: function (row, type, set) { return '<label class=\"checkbox i-checks\"><input type=\"checkbox\" name=\"cellCheckbox\" value=\"' + row.id + '\" /><i></i></label>'; }, \"bStorable\": false, width: 30 ,\"sClass\":'checkColumn'},");
            }
            if (dataList.Feature.HasFlag(ListFeature.RowNumber))
            {
                sb.AppendLine(
                    "{ title:'序号',data : null, bSortable : false, targets : 0, width : 50 ,\"sClass\":'rowNumberColumn',render : function(data, type, row, meta) { var startIndex = meta.settings._iDisplayStart; return startIndex + meta.row + 1; }},");
            }
            CamelCasePropertyNamesContractResolver cpncr = new CamelCasePropertyNamesContractResolver();
            foreach (var column in GetColumnInfos(model))
            {
                if (column.Value.Hidden) continue;

                List<string> plist = new List<string>();
                plist.Add("title: \"" + column.Value.Text + "\"");

                if (column.Value is DateColumnAttribute
                    && !((DateColumnAttribute)column.Value).Format.IsNullOrEmpty())
                {
                    plist.Add("data: function (row) { return new Date(row." + cpncr.GetResolvedPropertyName(column.Key) + ").format('" + ((DateColumnAttribute)column.Value).Format + "') }");
                }
                else if (column.Value is TemplateColumnAttribute)
                {
                    plist.Add("data: " + ((TemplateColumnAttribute)column.Value).TemplateString);
                }
                else
                {
                    plist.Add("data: \"" + cpncr.GetResolvedPropertyName(column.Key) + "\"");
                }
                if (column.Value.Width > 0)
                    plist.Add("width: " + column.Value.Width + "");

                plist.Add("\"sClass\": \"" + column.Value.Align.ToString().ToLower() + "\"");


                sb.AppendFormat("{{ {0}}},", string.Join(",", plist.ToArray()));
            }

            sb.AppendLine("]");
            sb.AppendLine("});");
            sb.AppendLine("});</script>");

            return sb.ToString();
        }

        private string IndexTree(object model)
        {
            var dataList = (ISharpTreeList)model;

            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("@model {0}\r\n", model.GetType().FullName);

            sb.AppendLine("@using Sharp.WebBooter");


            sb.AppendLine("<section class=\"content-header\">");

            sb.AppendLine("<h1>");

            sb.Append(dataList.GetTitle());
            sb.Append("</h1>");


            sb.AppendLine("<ol class=\"breadcrumb\">");
            sb.AppendLine("<li><a href =\"@Url.Action(\"Index\", \"Home\")\"><i class=\"fa fa-home\"></i> 首页</a></li>");
            sb.AppendLine("<li class=\"active\">VIU</li>");
            sb.AppendLine("</ol>");
            sb.AppendLine("</section>");
            sb.AppendLine("<section class=\"content\">");
            sb.AppendLine("<div class=\"row\">");
            sb.AppendLine("<div class=\"col-lg-12\">");
            sb.AppendLine("<div class=\"box box-primary\">");
            sb.AppendLine("<div class=\"box-header with-border\">");

            if (!dataList.Feature.HasFlag(ListFeature.HiddenToolButton))
            {
                sb.AppendLine("<div class=\"dataTable-tools btn-group\">");

                //渲染工具栏按钮
                var toolButtons = string.Join("\r\n", dataList.GetToolButtons(model).Select(x => x.Html));
                sb.AppendLine(toolButtons);
                sb.AppendLine("</div>");
            }


            sb.AppendLine("<div class=\"box-tools SearchArea\">");
            sb.AppendLine("<div class=\"input-group input-group-sm\" style=\"width:150px;float:right;\">");

            foreach (var column in GetColumnInfos(model))
            {
                if (column.Value.SearchFor)
                {
                    sb.AppendFormat("<input type =\"text\" name=\"{0}\" class=\"form-control pull-right\" placeholder=\"{1}\">\r\n", column.Key, column.Value.Text);
                }
            }
            sb.AppendLine("<div class=\"input-group-btn\">");
            sb.AppendLine("<button type =\"button\" class=\"btn btn-default\" onclick=\"window.app.search();\"><i class=\"fa fa-search\"></i></button>");
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("<div class=\"box-body no-padding\">");


            sb.AppendLine("<div class=\"table-responsive\">");
            sb.AppendLine("<table id=\"dataList\" class=\"table table-bordered table-striped table-condensed table-hover\">");
            sb.AppendLine("<thead><tr>");

            var treeColumn = 0;
            if (dataList.Feature.HasFlag(ListFeature.MultiSelect))
            {
                sb.AppendLine("<th style=\"width:43px;\" class=\"center\"><label class=\"m-l m-t-none m-b-none i-checks\"><input type=\"checkbox\" /><i></i></label></th>");
                treeColumn++;
            }
            foreach (var column in GetColumnInfos(model))
            {

                sb.AppendFormat("<th {1}>{0}</th>\r\n", column.Value.Text,
                    column.Value.Width > 0 ? "style=\"width:{1}px;\"" : "");

            }
            sb.AppendLine("                                </tr></thead>");
            sb.AppendLine("                            <tbody>");
            sb.AppendLine("                                @{");
            sb.AppendLine("                                    foreach (var item in Model.Data)");
            sb.AppendLine("                                    {");
            sb.AppendLine("                                        <tr class=\"@item.Itemclass\">");
            if (dataList.Feature.HasFlag(ListFeature.MultiSelect))
            {
                sb.AppendLine("<td style=\"width:43px;\" class=\"center\"><label class=\"m-l m-t-none m-b-none i-checks\"><input type=\"checkbox\" name=\"cellCheckbox\" value=\"@item.Id\" /><i></i></label></td>");
            }

            foreach (var column in GetColumnInfos(model))
            {
                if (column.Value.Hidden) continue;

                if (column.Value is DateColumnAttribute)
                {
                    sb.AppendFormat("<td>@item.{0}.ToString(\"\")</td>\r\n", column.Key);
                }
                else if (column.Value is TemplateColumnAttribute)
                {
                    sb.AppendFormat("<td>{0}</td>\r\n", ((TemplateColumnAttribute)column.Value).TemplateString);
                }
                else
                {
                    sb.AppendFormat("<td>@item.{0}</td>\r\n", column.Key);
                }
            }



            sb.AppendLine("                                        </tr>");
            sb.AppendLine("                                    }");
            sb.AppendLine("                                }");
            sb.AppendLine("</tbody></table>");


            sb.AppendLine("<script>$('#dataList').treegrid({ treeColumn: " + treeColumn + " });</script>");

            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("</section>");

            return sb.ToString();
        }
        #endregion

        #region 渲染界面

        /// <summary>
        /// 渲染界面
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="model"></param>
        /// <param name="title"></param>
        private void Rendering(StringBuilder sb, object model, string title)
        {
            sb.AppendFormat("@model {0}\r\n", model.GetType().FullName);

            sb.AppendLine("<div class=\"modal\">");
            sb.AppendLine("<div class=\"modal-dialog\">");
            sb.AppendLine("<div class=\"modal-content animated flipInY\">");
            sb.AppendLine("<div class=\"modal-header\">");
            sb.AppendLine("<button type=\"button\" class=\"close\" data-dismiss=\"modal\">");
            sb.Append("<span aria-hidden=\"true\"> &times; </span>");
            sb.AppendLine("<span class=\"sr-only\"> 关闭 </span></button>");
            if (model is BaseViewModel)
            {
                sb.AppendLine("<h4 class=\"modal-title\" id=\"myModalLabel\"> @Model.PageTitle </h4>");
            }
            else
            {
                sb.AppendFormat("<h4 class=\"modal-title\" id=\"myModalLabel\"> {0} </h4>", title);
            }
            sb.AppendLine("</div>");

            sb.AppendLine("<div class=\"modal-body\" id=\"modalcontent\">");
            sb.AppendLine("@using(Html.Bootstrap().BeginForm(c => c.Horizontal()))");
            sb.AppendLine("{");
            sb.AppendLine("@Html.ValidationSummary()");


            RendingEditing(sb, model);

            sb.AppendLine("}");
            sb.AppendLine("</div>");
            if (title != "详情")
            {
                sb.AppendLine("<div class=\"modal-footer\">");
                sb.AppendLine("@Html.Bootstrap().Button(\"保存\").Style(BootstrapStyle.Primary).Click(\"window.app.saveForm(event,'\" + @Url.Action(\"Save\") + \"');\")");
                sb.AppendLine(
                    "@Html.Bootstrap().Button(\"关闭\").Style(BootstrapStyle.Default).Attribute(\"data-dismiss\", \"modal\")");
                sb.AppendLine("</div>");
            }

            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");


            //ISharpForm from = model as ISharpForm;
            //if (from == null)
            //{
            //    //sb.AppendLine("            .Width(720)");
            //}
            //else
            //{
            //    //sb.AppendFormat("            .Width({0})", from.UI.Width);
            //}

        }

        private void RendingEditing(StringBuilder sb, object model)
        {
            bool fieldInserted = false;
            foreach (var property in model.GetType().GetProperties())
            {
                var customAttributes = property.GetCustomAttributes(false);
                if (!customAttributes.Any())
                {
                    continue;
                }
                if (customAttributes.Any(x => x is DataTypeAttribute))
                {
                    var dataType = customAttributes.First(x => x is DataTypeAttribute) as DataTypeAttribute;

                    if (dataType.DataType == DataType.Html)
                    {
                        sb.AppendLine("<div class=\"form-group\">");
                        sb.Append("@Html.LabelFor(m => m." + property.Name +
                                  ", new { @class = \"col-sm-2 control-label\" })");
                        sb.AppendLine("<div class=\"col-sm-10\">");
                        sb.Append("<textarea id=\"editor\" type=\"text\" cols=\"4\">@Model." + property.Name +
                                  "</textarea>");
                        sb.AppendLine("@Html.HiddenFor(m => m." + property.Name + ")");
                        sb.Append("</div>");
                        sb.AppendLine("</div>");
                        sb.AppendLine("<script type=\"text/javascript\">");
                        sb.AppendLine("$(\"#editor\").summernote({");
                        sb.AppendLine("            height: 250,");
                        sb.AppendLine("            lang: 'zh-CN',");
                        sb.AppendLine("            callbacks: {");
                        sb.AppendLine("                onKeyup: function () {");
                        sb.AppendLine("                    var content = $(\"#editor\").summernote(\"code\");");
                        sb.AppendLine("                    $(\"#" + property.Name + "\").val(content);");
                        sb.AppendLine("                },");
                        sb.AppendLine("                onblur: function (e) {");
                        sb.AppendLine("                    var content = $(\"#editor\").summernote(\"code\");");
                        sb.AppendLine("                    $(\"#" + property.Name + "\").val(content);");
                        sb.AppendLine("                }");
                        sb.AppendLine("            }");
                        sb.AppendLine("        });</script>");
                    }
                    else if (dataType.DataType == DataType.Upload)
                    {
                        //sb.AppendFormat("x.FileUploadField().DataIndex(\"{0}\").Text(\"{1}\").ColumnWidth(1).Padding(4),", property.Name, "");
                    }
                    else if (dataType.DataType == DataType.Date)
                    {
                        sb.AppendLine("<div class=\"form-group\">");
                        sb.Append("@Html.LabelFor(m => m." + property.Name +
                                  ", new { @class = \"col-sm-2 control-label\" })");
                        sb.AppendLine("<div class=\"col-sm-10\">");
                        sb.Append("@Html.Bootstrap().DateFor(m => m." + property.Name + ")");
                        sb.Append("</div>");
                        sb.AppendLine("</div>");
                    }
                    else if (dataType.DataType == DataType.DateTime)
                    {
                        //sb.Append("x.DateFieldFor(m => m." + property.Name + ").ColumnWidth(.5).Padding(4),");
                    }
                    else if (dataType.DataType == DataType.Time)
                    {
                        //sb.Append("x.TimeFieldFor(m => m." + property.Name + ").ColumnWidth(.5).Padding(4),");
                    }
                    else if (dataType.DataType == DataType.MultilineText)
                    {
                        sb.AppendLine("<div class=\"form-group\">");
                        sb.Append("@Html.LabelFor(m => m." + property.Name +
                                  ", new { @class = \"col-sm-2 control-label\" })");
                        sb.AppendLine("<div class=\"col-sm-10\">");
                        sb.Append("@Html.Bootstrap().TextareaFor(m => m." + property.Name + ")");
                        sb.Append("</div>");
                        sb.AppendLine("</div>");
                    }
                }
                else if (customAttributes.Any(x => x is HiddenInputAttribute))
                {
                    sb.AppendLine("@Html.HiddenFor(x => x." + property.Name + ")");
                }
                else if (customAttributes.Any(x => x is CustomFieldAttribute))
                {
                    //var customField = (CustomFieldAttribute)customAttributes.First(x => x is CustomFieldAttribute);
                    //if (customField.FieldType == FieldType.OrgList)
                    //{
                    //    sb.Append("x.DropDownFieldFor(m => m." + property.Name + ").OrgList(Model.OrgTree,\"" + customField.ValueHiddenName + "\").Editable(false).ColumnWidth(.5).Padding(4),");
                    //    sb.AppendFormat("x.HiddenFor(f=>f.{0}),", customField.ValueHiddenName);
                    //}
                }
                else
                {
                    sb.AppendLine("<div class=\"form-group\">");
                    sb.AppendFormat("@Html.LabelFor(m => m.{0}, new {{ @class = \"col-sm-2 control-label\" }})", property.Name);
                    sb.AppendLine("<div class=\"col-sm-10\">");
                    sb.AppendFormat("@Html.Bootstrap().TextBoxFor(m => m.{0})", property.Name);
                    sb.Append("</div>");
                    sb.AppendLine("</div>");
                }
                fieldInserted = true;
            }

            if (fieldInserted)
            {
                sb.Remove(sb.Length - 1, 1);
            }
            sb.AppendLine();
        }
        private void RendingReading(StringBuilder sb, object model) { }
        #endregion

        //用来缓存模型定义
        private static readonly ConcurrentDictionary<Type, Dictionary<string, ColumnAttribute>> _columnInfos =
            new ConcurrentDictionary<Type, Dictionary<string, ColumnAttribute>>();
        /// <summary>
        /// 获取模型的列定义
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private Dictionary<string, ColumnAttribute> GetColumnInfos(object model)
        {
            Type modelType = model.GetType();

            var outPut = _columnInfos.GetOrAdd(modelType, new Dictionary<string, ColumnAttribute>());
            if (outPut.Count > 0)
            {
                return outPut;
            }

            foreach (var property in modelType.GetProperties())
            {
                var column =
                    property.GetCustomAttributes(typeof(ColumnAttribute), false).FirstOrDefault() as ColumnAttribute;
                if (column == null) continue;

                outPut.Add(property.Name, column);
            }

            outPut = outPut.OrderBy(x => x.Value.Order)//.ThenByDescending(x => x.Key)
                .ToDictionary(k => k.Key, v => v.Value);

            return outPut;
        }
    }
}